/**
 * Copyright 2010 Victor Egea Hernando
 *
 * RockScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * RockScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with RockScript.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "pjit_buffer.h"

#include "targets/x86/pjit_codegen_x86.h"
#include "targets/arm/pjit_codegen_arm.h"

#include <ostream>

namespace pjit{

pjit_buffer::pjit_buffer( void ){
	_nlabel = 0; _quad_it = _lir.begin();
	// get code generator
	#if PICOJIT_TARGET == 1 || PICOJIT_TARGET == 2
		_codegen = new pjit_codegen_x86();
	#elif PICOJIT_TARGET == 3
		_codegen = new pjit_codegen_arm();
	#endif
}

pjit_buffer::~pjit_buffer(){
	delete _codegen;
}

uint32 pjit_buffer::next_label( void ){
	return ( _nlabel++ );
}

std::list<pjit_buffer::__lir_quad>::iterator pjit_buffer::end_quad( void ){
	return( _lir.end() );
}

std::list<pjit_buffer::__lir_quad>::iterator pjit_buffer::next_quad( void ){
	_quad_it++; return( _quad_it );
}

std::list<pjit_buffer::__lir_quad>::iterator pjit_buffer::begin_quad( void ){
	_quad_it = _lir.begin(); return( _quad_it );
}

uint32 pjit_buffer::size( void ) const{
	return( _lir.size() );
}

pjit_buffer &pjit_buffer::compile( pjit_block &block ){
	// compile
	_codegen->compile( block, *this );
	// delete codegen & return
	return ( *this );
}

pjit_buffer &pjit_buffer::lir_loadi32( int32 val, uint32 rt ){
	__lir_quad lq; lq.rs1.vint32 = val; lq.op = loadi32; lq.rt = rt;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_loadr32( real32 val, uint32 rt ){
	__lir_quad lq; lq.rs1.vreal32 = val; lq.op = loadr32; lq.rt = rt;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_loadi32p( int32 *valp, uint32 rt ){
	__lir_quad lq; lq.rs1.pint32 = valp; lq.op = loadi32p; lq.rt = rt;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_loadr32p( real32 *valp, uint32 rt ){
	__lir_quad lq; lq.rs1.preal32 = valp; lq.op = loadr32p; lq.rt = rt;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_loadptr( void *valp, uint32 rt ){
	__lir_quad lq; lq.rs1.pvoid = valp; lq.op = loadptr; lq.rt = rt;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_label( uint32 lab ){
	__lir_quad lq; lq.rs1.vuint32 = lab; lq.op = label;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_cjmp( uint32 lab ){
	__lir_quad lq; lq.rs1.vuint32 = lab; lq.op = cjmp;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_jmp( uint32 lab ){
	__lir_quad lq; lq.rs1.vuint32 = lab; lq.op = jmp;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_pusharg32( uint32 rs1 ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.op = pusharg32;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_pushargptr( void *dir ){
	__lir_quad lq; lq.rs1.pvoid = dir; lq.op = pushargptr;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_pushargregref( uint32 rs1 ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.op = pushargregref;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_call( void *dir ){
	__lir_quad lq; lq.rs1.pvoid = dir; lq.op = call;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_ret( void ){
	__lir_quad lq; lq.op = ret;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_addi( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = addi;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_subi( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = subi;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_muli( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = muli;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_divi( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = divi;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_addr( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = addr;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_subr( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = subr;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_mulr( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = mulr;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_divr( uint32 rs1, uint32 rs2, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rs2 = rs2; lq.rt = rt; lq.op = divr;
	_lir.push_back( lq ); return ( *this );
}

pjit_buffer &pjit_buffer::lir_sqrtr( uint32 rs1, uint32 rt ){
	__lir_quad lq; lq.rs1.vuint32 = rs1; lq.rt = rt; lq.op = sqrtr;
	_lir.push_back( lq ); return ( *this );
}

}; // namespace pjit
